/*
     Copyright 2007 Joseph M. Ferner

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System.Collections.Generic;
using OpenServers.Net.Common;
using OpenServers.Net.Common.FileSystem;
using OpenServers.Net.Common.Listener;
using OpenServers.Net.Common.Security;
using OpenServers.Net.Common.Socket;
using OpenServers.Net.Common.State;
using OpenServers.Net.HttpServer.Response;
using OpenServers.Net.HttpServer.State;

namespace OpenServers.Net.HttpServer {
    /// <summary>
    /// HTTP Server for serving web pages to a web client such as a browser.
    /// </summary>
    public class HttpServer : AbstractServer, IHttpServer {
        /// <summary>
        /// Default nonsecure port number.
        /// </summary>
        public const int DEFAULT_NONSECURE_PORT = 80;

        private IFileSystem _fileSystem;
        private ISecurityProvider _securityProvider;
        private readonly IList<string> _defaultPages = new List<string>();
        private readonly IHttpProcessor _httpProcessor;

        /// <summary>
        /// default constructor. Adds a list of default pages to use if a directory is requested.
        /// </summary>
        public HttpServer() {
            InitializeState += MyInitializeState;

            _defaultPages.Add("index.html");
            _defaultPages.Add("index.htm");

            _httpProcessor = new HttpProcessor(this);
        }

        private void MyInitializeState(IServer server, IState state) {
            state.ConnectionOpened += ConnectionOpened;
            state.DataReceived += DataReceived;
        }

        private void ConnectionOpened(IState stateArg) {
            HttpState state = (HttpState)stateArg;
            state.User = _securityProvider.ValidateUser(null, null);
            state.Response = new HttpResponse();
            state.RequestState = HttpState.RequestStateEnum.Header;
        }

        private void DataReceived(IState stateArg, byte[] buffer, int bytesRead) {
            HttpState state = (HttpState)stateArg;
            if (state.RequestState == HttpState.RequestStateEnum.Header) {
                _httpProcessor.DataReceived(state, buffer, bytesRead);
            }
            if (state.RequestState == HttpState.RequestStateEnum.Body) {
                _httpProcessor.ProcessBody(state, buffer, bytesRead);
            }
            if (state.RequestState == HttpState.RequestStateEnum.BodyComplete) {
                _httpProcessor.SendResponse(state);
            }
        }


        /// <summary>
        /// The name of the server sent back in the http headers.
        /// </summary>
        public virtual string ServerName {
            get {
                string versionString = typeof(HttpServer).Assembly.GetName().Version.ToString();
                return string.Format("OpenServers.Net HttpServer/{0}", versionString);
            }
        }

        /// <summary>
        /// The list of default pages. (i.e. index.html, index.htm, etc.)
        /// </summary>
        public IEnumerable<string> DefaultPages {
            get { return _defaultPages; }
        }

        /// <summary>
        /// Creates a state object used in processing a request.
        /// </summary>
        public override IState CreateState(IListener listener, ISocket clientSocket) {
            return new HttpState(listener, clientSocket);
        }

        /// <summary>
        /// The backing file system for served up files.
        /// </summary>
        public IFileSystem FileSystem {
            get { return _fileSystem; }
            set { _fileSystem = value; }
        }

        /// <summary>
        /// The security provider protecting resources.
        /// </summary>
        public ISecurityProvider SecurityProvider {
            get { return _securityProvider; }
            set { _securityProvider = value; }
        }
    }
}
